package org.fastsyncer.plugin.impl;

import java.util.List;
import java.util.Map;

import javax.naming.NamingException;

import org.apache.commons.lang.StringUtils;
import org.fastsyncer.common.constant.ConnectorConstant;
import org.fastsyncer.common.entity.LdapConfig;
import org.fastsyncer.common.entity.Mapping;
import org.fastsyncer.common.entity.MappingTask;
import org.fastsyncer.connector.ldap.LdapConnector;
import org.fastsyncer.plugin.AbstractConvert;
import org.fastsyncer.plugin.impl.pool.DatabasePool;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.ldap.AuthenticationException;
import org.springframework.ldap.CommunicationException;
import org.springframework.ldap.core.LdapTemplate;

/**
 * <ul>
 * <dt>星盾Ldap目录岗位转换规则：</dt>
 *  <dl>
 *      <li>找到岗位的所在的组织</li>
 *      <li>生成组织层级关系>ou=星盾产品部,ou=中电启明星</li>
 *      <li>生成岗位层级关系>ou=研发岗位</li>
 *      <li>生成岗位完整路径>组织层级关系+岗位层级关系</li>
 *  </dl>
 * </ul>
 * 
 * @author AE86
 * @date 2018年02月23日 下午13:59:01
 * @version 1.0.0
 */
public class AostarLdapPostConvertImpl extends AbstractConvert {

    private final Logger logger = LoggerFactory.getLogger(AostarLdapPostConvertImpl.class);

    private final String OU = "ou";

    /**
     * 岗位编码
     */
    private final String POST_CODE = "POST_CODE";

    /**
     * 岗位名称
     */
    private final String POST_NAME = "POST_NAME";

    /**
     * 企业组织ID
     */
    private final String BASEORG_ID = "BASEORG_ID";

    /**
     * 标识HR数据，1表示是，其它否
     */
    private final String FROM_HR = "FROM_HR";

    /**
     * 企业组织上级ID
     */
    private final String PARENT_ID = "PARENT_ID";

    /**
     * 企业组织名称
     */
    private final String BASEORG_NAME = "BASEORG_NAME";

    /**
     * 根据ID查询企业组织
     * <pre>
     * SELECT ID,PARENT_ID,BASEORG_NAME FROM SD_BASEORG WHERE IS_DELETED = '0' AND ID = ?
     * </pre>
     */
    private final String QUERY_BASEORG_BY_ID = "SELECT ID,PARENT_ID,BASEORG_NAME FROM SD_BASEORG WHERE IS_DELETED = '0' AND ID = ?";

    @Override
    public String getConvertName() {
        return "企业岗位_港中旅目录岗位转换";
    }

    @Override
    public void convert(MappingTask task, List<Map<String, Object>> source, List<Map<String, Object>> target) {
        String dn = this.getDn(task);
        if (StringUtils.isBlank(dn)) {
            return;
        }

        // 创建连接池
        DatabasePool pool = DatabasePool.getInstance();
        String uuid = pool.create(task.getSourceMapping());
        if (StringUtils.isBlank(uuid)) {
            return;
        }
        try {
            // 获取数据库连接
            JdbcTemplate jdbc = pool.get(uuid);
            if (null == jdbc) {
                return;
            }
            // 转换为树形结构
            this.buildTree(dn, source, target, jdbc);
        } catch (Exception e) {
            logger.info(e.getClass() + " >> " + e.getLocalizedMessage());
        } finally {
            pool.close(uuid);
        }
    }

    @Override
    public void convert(MappingTask task, Map<String, Object> source, Map<String, Object> target, String event, Map<String, Object> beforeData) {
        String dn = this.getDn(task);
        if (StringUtils.isBlank(dn)) {
            return;
        }

        // 创建连接池
        DatabasePool pool = DatabasePool.getInstance();
        String uuid = pool.create(task.getSourceMapping());
        if (StringUtils.isBlank(uuid)) {
            return;
        }
        try {
            // 获取数据库连接
            JdbcTemplate jdbc = pool.get(uuid);
            if (null == jdbc) {
                return;
            }
            // 转换为树形结构
            this.buildTree(task, event, dn, source, target, jdbc, beforeData);
        } catch (Exception e) {
            logger.info(e.getClass() + " >> " + e.getLocalizedMessage());
        } finally {
            pool.close(uuid);
        }
    }

    /**
     * 获取目录的dn
     * @param task
     * @return
     */
    private String getDn(MappingTask task) {
        Mapping targetMapping = task.getTargetMapping();
        String connector = targetMapping.getConnector();
        if (!ConnectorConstant.LDAP_CONNECTOR.equals(connector)) {
            return null;
        }
        // 获取目录dn
        LdapConfig config = (LdapConfig) targetMapping.getConfig();
        return config.getDn();
    }

    private void buildTree(String dn, List<Map<String, Object>> source, List<Map<String, Object>> target, JdbcTemplate jdbc) {
        // 获取总条数
        int sourceSize = source.size();
        int targetSize = target.size();
        if (sourceSize != targetSize) {
            return;
        }

        Map<String, Object> sNode = null;
        Map<String, Object> tNode = null;
        String postCode;
        String postName;
        String baseorgId;
        StringBuilder path;
        String fromHR;
        for (int i = 0; i < targetSize; i++) {
            sNode = source.get(i);
            tNode = target.get(i);
            // 1.生成组织的层级关系(ou=星盾产品部,ou=中电启明星)
            // 岗位名称
            postCode = String.valueOf(sNode.get(POST_CODE));
            // 岗位名称
            postName = String.valueOf(sNode.get(POST_NAME));
            // 企业组织ID
            baseorgId = String.valueOf(sNode.get(BASEORG_ID));
            // 标识HR数据，1表示是，其它否
            fromHR = String.valueOf(sNode.get(FROM_HR));
            // 定义父节点dn全路径,ou=星盾产品部,ou=中电启明星
            path = this.getPath(dn, new StringBuilder(), baseorgId, jdbc);

            // 2.拼接ou全路径
            path = this.buildName(jdbc, path, dn, postCode, postName, baseorgId, fromHR);

            // 3.设置ldap的ou值为岗位的全路径
            tNode.put(OU, path.toString());
        }

    }

    private void buildTree(MappingTask task, String event, String dn, Map<String, Object> source, Map<String, Object> target, JdbcTemplate jdbc, Map<String, Object> beforeData) throws AuthenticationException, CommunicationException, NamingException {
        // 1.生成组织的层级关系(ou=星盾产品部,ou=中电启明星)
        // 企业组织ID
        String postCode = String.valueOf(source.get(POST_CODE));
        String baseorgId = String.valueOf(source.get(BASEORG_ID));
        String postName = String.valueOf(source.get(POST_NAME));
        String fromHR = String.valueOf(source.get(FROM_HR));
        // 定义父节点dn全路径
        StringBuilder parentPath = this.getPath(dn, new StringBuilder(), baseorgId, jdbc);

        // 2.拼接更新后的dn全路径,ou=org,dc=aostar,dc=com
        String newDn = this.buildName(jdbc, parentPath, dn, postCode, postName, baseorgId, fromHR).toString();

        // 3.计算dn是否有变更
        // 由于港中旅的目录dn路径是用的组织名称,而组织名称有可能会发生变更,导致修改的数据无法找到原目录的dn路径
        // 故此,如果发生修改操作时,保证组织名称变化前后一致
        if (ConnectorConstant.OPERTION_UPDATE.equals(event)) {
            this.refeshDn(jdbc, task, beforeData, dn, parentPath, newDn, postName);
        }

        // 4.设置dn为节点全路径
        target.put(OU, newDn);
    }

    private StringBuilder getPath(String dn, StringBuilder path, String id, JdbcTemplate jdbc) {
        // 获取父节点
        Map<String, Object> node;
        try {
            node = jdbc.queryForMap(QUERY_BASEORG_BY_ID, new Object[] { id });
        } catch (DataAccessException e) {
            node = null;
        }
        if (null == node) {
            return path;
        }

        String name = String.valueOf(node.get(BASEORG_NAME));
        String pid = String.valueOf(node.get(PARENT_ID));
        // ,ou=开发岗位
        path.append(",").append(dn).append("=").append(name);
        return getPath(dn, path, pid, jdbc);
    }

    private void refeshDn(JdbcTemplate jdbc, MappingTask task, Map<String, Object> beforeData, String dn, StringBuilder parentPath, String newDn, String newName) throws AuthenticationException, CommunicationException, NamingException {
        // 1.判断是否修改组织名称
        String oldName = String.valueOf(beforeData.get(POST_NAME));
        if (oldName.equals(newName)) {
            return;
        }

        // 2.拼接旧dn
        String postCode = String.valueOf(beforeData.get(POST_CODE));
        String oldBaseorgId = String.valueOf(beforeData.get(BASEORG_ID));
        String oldFromHR = String.valueOf(beforeData.get(FROM_HR));
        StringBuilder oldDn = this.buildName(jdbc, parentPath, dn, postCode, oldName, oldBaseorgId, oldFromHR);

        // 3.修改为最新的dn
        Mapping targetMapping = task.getTargetMapping();
        LdapConfig c = (LdapConfig) targetMapping.getConfig();
        LdapTemplate ldapTemplate = LdapConnector.getInstance().getLdapTemplate(c);
        ldapTemplate.rename(oldDn.toString(), newDn);
    }

    private StringBuilder buildName(JdbcTemplate jdbc, StringBuilder parentPath, String dn, String postCode, String postName, String baseorgId, String fromHR) {
        // 默认格式：ou=开发岗位
        StringBuilder ouName = new StringBuilder(dn).append("=").append(postName);
        // 如果是HR数据，ou格式：岗位名称-岗位编码
        if (StringUtils.equals("1", fromHR)) {
            try {
                ouName.append("-").append(postCode);
            } catch (Exception e) {
            }
        }
        // ou=开发岗位,ou=星盾产品部,ou=中电启明星
        return parentPath.insert(0, ouName);
    }

}
